package com.sdhs.paas.internet.util.regex;

import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

public class ClassNameWildcardCompiler
{
  public static final int MATCH_PREFIX = 4096;
  private static final char ESCAPE_CHAR = '\\';
  private static final char DOT = '.';
  private static final char UNDERSCORE = '_';
  private static final char DOLLAR = '$';
  private static final char STAR = '*';
  private static final char QUESTION = '?';
  private static final String REGEX_MATCH_PREFIX = "^";
  private static final String REGEX_WORD_BOUNDARY = "\\b";
  private static final String REGEX_DOT = "\\.";
  private static final String REGEX_DOT_NO_DUP = "\\.(?!\\.)";
  private static final String REGEX_CLASS_NAME_CHAR = "[\\w\\$]";
  private static final String REGEX_CLASS_NAME_SINGLE_CHAR = "([\\w\\$])";
  private static final String REGEX_CLASS_NAME = "([\\w\\$]*)";
  private static final String REGEX_CLASS_NAME_FULL = "([\\w\\$]+(?:\\.(?!\\.)[\\w\\$]*)*(?=\\.|$)|)\\.?";
  private static final int LAST_TOKEN_START = 0;
  private static final int LAST_TOKEN_DOT = 1;
  private static final int LAST_TOKEN_CLASS_NAME = 2;
  private static final int LAST_TOKEN_STAR = 3;
  private static final int LAST_TOKEN_DOUBLE_STAR = 4;
  private static final int LAST_TOKEN_QUESTION = 5;

  public static Pattern compileClassName(String pattern)
    throws PatternSyntaxException
  {
    return compileClassName(pattern, 0);
  }

  public static Pattern compileClassName(String pattern, int options)
    throws PatternSyntaxException
  {
    return Pattern.compile(classNameToRegex(pattern, options), options);
  }

  public static int getClassNameRelevancy(String pattern)
  {
    pattern = normalizeClassName(pattern);

    if (pattern == null) {
      return 0;
    }

    int relevant = 0;

    for (int i = 0; i < pattern.length(); i++) {
      switch (pattern.charAt(i)) {
      case '*':
      case '.':
      case '?':
        break;
      default:
        relevant++;
      }
    }

    return relevant;
  }

  public static String classNameToRegex(String pattern, int options)
    throws PatternSyntaxException
  {
    pattern = normalizeClassName(pattern);

    int lastToken = 0;
    StringBuilder buffer = new StringBuilder(pattern.length() * 2);

    boolean matchPrefix = (options & 0x1000) != 0;

    if (matchPrefix) {
      buffer.append("^");
    }

    for (int i = 0; i < pattern.length(); i++) {
      char ch = pattern.charAt(i);

      switch (ch)
      {
      case '.':
        if ((lastToken == 1) || (lastToken == 0)) {
          throw new PatternSyntaxException("Syntax Error", pattern, i);
        }

        if (lastToken != 4) {
          buffer.append("\\.(?!\\.)");
        }

        lastToken = 1;
        break;
      case '*':
        int j = i + 1;

        if ((j < pattern.length()) && (pattern.charAt(j) == '*')) {
          i = j;

          if ((lastToken != 0) && (lastToken != 1)) {
            throw new PatternSyntaxException("Syntax Error", pattern, i);
          }

          lastToken = 4;
          buffer.append("([\\w\\$]+(?:\\.(?!\\.)[\\w\\$]*)*(?=\\.|$)|)\\.?");
        }
        else {
          if ((lastToken == 3) || (lastToken == 4)) {
            throw new PatternSyntaxException("Syntax Error", pattern, i);
          }

          lastToken = 3;
          buffer.append("([\\w\\$]*)");
        }

        break;
      case '?':
        lastToken = 5;
        buffer.append("([\\w\\$])");
        break;
      default:
        if (lastToken == 4) {
          throw new PatternSyntaxException("Syntax Error", pattern, i);
        }

        if ((Character.isLetterOrDigit(ch)) || (ch == '_'))
        {
          if (lastToken == 0)
            buffer.append("\\b").append(ch);
          else if (i + 1 == pattern.length())
            buffer.append(ch).append("\\b");
          else
            buffer.append(ch);
        }
        else if (ch == '$')
          buffer.append('\\').append('$');
        else {
          throw new PatternSyntaxException("Syntax Error", pattern, i);
        }

        lastToken = 2;
      }
    }

    return buffer.toString();
  }

  public static String normalizeClassName(String name)
  {
    if (name == null) {
      return null;
    }

    name = name.trim();
    name = name.replaceAll("[/\\\\\\.]+", ".");
    name = name.replaceAll("^\\.|\\.$", "");

    return name;
  }

  public static String classNameToPathName(String name)
  {
    name = normalizeClassName(name);

    if (name == null) {
      return null;
    }

    name = name.replace('.', '/');

    return name;
  }
}